//
// Created by LM on 2025/5/18.
//

#include <string.h>
#include "uart_dma.h"
//
// Created by LM on 2025/5/18.
//

#include "uart_dma.h"
#include "../gd32f4xx.h"
#include "uart_dma.h"
#include "cli/cli_setup.h"


#define UART_DMA_TX_CHANNEL_MAX 2
#define UART_DMA_TX_BUFFER_BYTE 2*1024

#define UART_DMA_RX_BUFFER_BYTE 2*1024

// 不考虑发送频繁覆盖的问题
static uint8_t uart_dma_tx_buffer[UART_DMA_TX_CHANNEL_MAX][UART_DMA_TX_BUFFER_BYTE] = {0};
static uint8_t uart_dma_rx_buffer[UART_DMA_TX_CHANNEL_MAX][UART_DMA_RX_BUFFER_BYTE] = {0};

static UART_DMA_CONFIG_T uart_dma_config[UART_DMA_TX_CHANNEL_MAX] = {
        {
                .uart_n = USART0,
                .tx_dma_stream = DMA1,
                .tx_dma_channel = DMA_CH7,
                .tx_mem_addr = (uint32_t) uart_dma_tx_buffer[0],
                .tx_dma_peripheral = DMA_SUBPERI4,

                .rx_dma_stream = DMA1,
                .rx_dma_channel = DMA_CH5,
                .rx_mem_addr = (uint32_t) uart_dma_rx_buffer[0],
                .tx_dma_peripheral = DMA_SUBPERI4,
        },
        {
                .uart_n = USART1,
                .tx_dma_stream = DMA0,
                .tx_dma_channel = DMA_CH6,
                .tx_mem_addr = (uint32_t) uart_dma_tx_buffer[1],
                .tx_dma_peripheral = DMA_SUBPERI4,

                .rx_dma_stream = DMA0,
                .rx_dma_channel = DMA_CH5,
                .rx_mem_addr = (uint32_t) uart_dma_rx_buffer[1],
                .rx_dma_peripheral = DMA_SUBPERI4,
        },
};

void uart_dma_init(void) {
    dma_single_data_parameter_struct dma_init_struct;
    dma_single_data_parameter_struct dma_rx_init_struct;
    // 配置 USART1/USART2/USART5 DMA TX
    rcu_periph_clock_enable(RCU_DMA0);
    rcu_periph_clock_enable(RCU_DMA1);

    dma_init_struct.circular_mode = DMA_CIRCULAR_MODE_DISABLE;
    dma_init_struct.direction = DMA_MEMORY_TO_PERIPH;
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_8BIT;
    dma_init_struct.number = UART_DMA_TX_BUFFER_BYTE;
    dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;

    dma_rx_init_struct.circular_mode = DMA_CIRCULAR_MODE_DISABLE;
    dma_rx_init_struct.direction = DMA_PERIPH_TO_MEMORY;
    dma_rx_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_rx_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_8BIT;
    dma_rx_init_struct.number = UART_DMA_TX_BUFFER_BYTE;
    dma_rx_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
    dma_rx_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;

    for (int32_t i = 0; i < UART_DMA_TX_CHANNEL_MAX; i++) {
        UART_DMA_CONFIG_T *config = &uart_dma_config[i];
        dma_deinit(config->tx_dma_stream, config->tx_dma_channel);
        dma_init_struct.memory0_addr = config->tx_mem_addr;
        dma_init_struct.periph_addr = (uint32_t) &USART_DATA(config->uart_n);
        dma_single_data_mode_init(config->tx_dma_stream, config->tx_dma_channel, dma_init_struct);
        /* configure DMA mode */
        dma_circulation_disable(config->tx_dma_stream, config->tx_dma_channel);
        dma_channel_subperipheral_select(config->tx_dma_stream, config->tx_dma_channel, config->tx_dma_peripheral);
        usart_dma_transmit_config(config->uart_n, USART_DENT_ENABLE);

        dma_deinit(config->rx_dma_stream, config->rx_dma_channel);
        dma_rx_init_struct.memory0_addr = config->rx_mem_addr;
        dma_rx_init_struct.periph_addr = (uint32_t) &USART_DATA(config->uart_n);
        dma_single_data_mode_init(config->rx_dma_stream, config->rx_dma_channel, dma_rx_init_struct);
        /* configure DMA mode */
        dma_circulation_disable(config->rx_dma_stream, config->rx_dma_channel);
        dma_channel_subperipheral_select(config->rx_dma_stream, config->rx_dma_channel, config->rx_dma_peripheral);
        dma_channel_enable(config->rx_dma_stream, config->rx_dma_channel);
        usart_dma_receive_config(config->uart_n, USART_DENR_ENABLE);
    }
}

void uart_dma_tx_send_uart_x(uint32_t uart_x, uint8_t *data, uint16_t len) {
    for (int32_t i = 0; i < sizeof(uart_dma_config) / sizeof(uart_dma_config[0]); i++) {
        UART_DMA_CONFIG_T *config = &uart_dma_config[i];
        if (config->uart_n == uart_x) {
            memcpy((void *) config->tx_mem_addr, data, len);

            dma_channel_disable(config->tx_dma_stream, config->tx_dma_channel);
            dma_flag_clear(config->tx_dma_stream, config->tx_dma_channel, DMA_INTF_FTFIF);
            DMA_CHCNT(config->tx_dma_stream, config->tx_dma_channel) = len;
            dma_channel_enable(config->tx_dma_stream, config->tx_dma_channel);
        }
    }
}


void uart_dma_handle_rx(uint32_t uart_x) {
    UART_DMA_CONFIG_T *config = NULL;
    for (int32_t i = 0; i < sizeof(uart_dma_config) / sizeof(uart_dma_config[0]); i++) {
        if (uart_dma_config[i].uart_n == uart_x) {
            config = &uart_dma_config[i];
            break;
        }
    }

    if (config == NULL) {
        return;
    }

    uint16_t len = UART_DMA_RX_BUFFER_BYTE - DMA_CHCNT(config->rx_dma_stream, config->rx_dma_channel);
    uint8_t *rx_buf_prt = (uint8_t *) config->rx_mem_addr;

    for (int32_t i = 0; i < len; i++) {
        on_cli_receive_char(rx_buf_prt[i]);
    }
}

